#include "RedisConPool.h"
#include "../../ConfigMgr.h"
#include "../../log.h"

RedisConPool::RedisConPool():_b_stop(false)
{
    auto config = ConfigMgr::GetConfig();
    _poolSize = config->RedisInfo.PoolSize;
    _port = config->RedisInfo.Port;
    _host = config->RedisInfo.IP;
    _pwd = config->RedisInfo.Pwd;

    for (size_t i = 0; i < _poolSize; ++i) 
    {
        auto ctx = _CreateContext();
        if (ctx) {
            _connections.push(std::move(ctx));
        }
    }
}

RedisConPool::ContextPtr RedisConPool::_CreateContext() 
{
    redisContext* raw = redisConnect(_host.c_str(), _port);
    if (!raw || raw->err) 
    {
        if (raw) redisFree(raw);
        log_error("Redis connect failed");
        exit(-1);
    }
    auto reply = (redisReply*)redisCommand(raw, "AUTH %s", _pwd.c_str());
    if (!reply || reply->type == REDIS_REPLY_ERROR) 
    {
        if (reply) freeReplyObject(reply);
        redisFree(raw);
        log_error("Redis auth failed: {}", reply ? reply->str : "No reply");
        exit(-1);
    }
    freeReplyObject(reply);
    log_info("Redis auth success");
    return ContextPtr(raw);
}

void RedisConPool::_ReturnConnection(ContextPtr ctx)
{
    if (!ctx || _b_stop) return;
    std::lock_guard<std::mutex> lock(_mutex);
    _connections.push(std::move(ctx));
    _cond.notify_one();
}


RedisConPool::ConnectionHandle RedisConPool::GetConnection() 
{
    std::unique_lock<std::mutex> lock(_mutex);
    _cond.wait(lock, [this] { 
        return _b_stop || !_connections.empty(); 
    });

    if (_b_stop) return ConnectionHandle(*this, nullptr);

    //取出链接
    auto ctx = std::move(_connections.front());
    _connections.pop();

    return ConnectionHandle(*this, std::move(ctx));
}

void RedisConPool::Close() {
    {
        std::lock_guard<std::mutex> lock(_mutex);
        _b_stop = true;
        while (!_connections.empty()) {
            _connections.pop(); // ContextPtr 自动调用 redisFree
        }
    }
    _cond.notify_all();
}

void RedisConPool::show() {
    log_info("redis pool port: {}", _port);
    log_info("redis pool host: {}", _host);
    log_info("redis pool is stop: {}", _b_stop ? "true" : "false");
    log_info("redis pool size: {}", _poolSize);
}